package com.nulldev.util.web.flexibleKit.scfk.protocols.http1;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.List;
import java.util.Map;

import com.nulldev.util.VariableAPI.ArrayUtils;
import com.nulldev.util.VariableAPI.MathUtil;
import com.nulldev.util.VariableAPI.util.strings.splitters.Splitters;
import com.nulldev.util.data.Arrays.arrays.FastLists;
import com.nulldev.util.data.Arrays.maps.FastMaps;
import com.nulldev.util.internal.backport.concurrency9.Lists;
import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;
import com.nulldev.util.web.URLUtils.fparser.URL;
import com.nulldev.util.web.flexibleKit.scfk.SCFKRequest;
import com.nulldev.util.web.flexibleKit.scfk.SCFKResponse;
import com.nulldev.util.web.flexibleKit.scfk.io.ChunkedInputStream;
import com.nulldev.util.web.flexibleKit.scfk.io.streams.Stream;
import com.nulldev.util.web.flexibleKit.scfk.io.streams.StreamGenerator;
import com.nulldev.util.web.flexibleKit.scfk.protocols.PreferredProtocol;
import com.nulldev.util.web.flexibleKit.scfk.protocols.ProtocolResponse;
import com.nulldev.util.web.flexibleKit.scfk.protocols.RedirectionPolicy;
import com.nulldev.util.web.flexibleKit.scfk.utils.SCFKIOUtils;

public class Http1Response implements ProtocolResponse {

	protected static final Http1Response INSTANCE = new Http1Response();
	private static final Logger log = LoggerFactory.getLogger();

	@SuppressWarnings("resource")
	@Override
	public SCFKResponse onResponseRead(final SCFKRequest r, final Stream s) throws Exception {
		final Map<String, List<String>> headers = FastMaps.map(15);
		final InputStream is = SCFKIOUtils.make(s);
		log.debug("is.av: " + is.available());
		final String rl = readTillNextLine(is);
		log.debug(rl);
		final String[] rl_arr = Splitters.splitString(rl, " ");
		final String httpVer = rl_arr[0];
		final String httpRspCode_s = rl_arr[1];
		final int httpRspCode = MathUtil.safeParseInt(httpRspCode_s, -1);
		final PreferredProtocol pp = PreferredProtocol.get(httpVer);
		if (httpRspCode == -1)
			log.warn("Unknown response code: " + httpRspCode_s);
		if (r.getProtocol().protVersion > 0.9) {
			String header;
			while ((header = readTillNextLine(is)) != null) {
				final String[] sp = Splitters.splitString(header, ": ");
				if (sp.length <= 1)
					break;
				if (headers.containsKey(sp[0])) {
					headers.get(sp[0]).add(ArrayUtils.StringArrayUtils.addFrom(sp, 1));
				} else
					headers.put(sp[0], FastLists.list(Lists.of(ArrayUtils.StringArrayUtils.addFrom(sp, 1))));
			}
			if (log.isDebugEnabled()) {
				ArrayUtils.printLln(headers);
			}
		}
		if (headers.containsKey("Connection") && headers.get("Connection").get(0).equalsIgnoreCase("keep-alive")) {
			s.setKeepAlive(true);
		} else if (s.shouldKeepAlive() && headers.containsKey("Connection") && headers.get("Connection").get(0).equalsIgnoreCase("Close")) {
			s.setKeepAlive(false);
		}
		if ((httpRspCode == 302 || httpRspCode == 301 || httpRspCode == 303) && r.redirectionPolicy() != RedirectionPolicy.NEVER
				&& headers.containsKey("Location")) {
			final String to = headers.get("Location").get(0).replace(" //", "://");
			final URL url = URL.parse(to);
			r.updateURL(url);
			s.closeIfNeeded();
			if (r.redirectionPolicy() == RedirectionPolicy.IF_SECURE && url.getScheme().equalsIgnoreCase("https")) {
				return Http1Request.INSTANCE.onRequestWrite(r, StreamGenerator.autoStream(r));
			} else {
				return Http1Request.INSTANCE.onRequestWrite(r, StreamGenerator.autoStream(r));
			}
		}
		if (headers.containsKey("Transfer-Encoding") && headers.get("Transfer-Encoding").get(0).equalsIgnoreCase("chunked")) {
			return new SCFKResponse(pp, httpRspCode, headers, s, new ChunkedInputStream(is, headers), r);
		} else {
			return new SCFKResponse(pp, httpRspCode, headers, s, is, r);
		}
	}

	private String readTillNextLine(final InputStream is) throws Exception {
		final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(1024);
		int c;
		while ((c = is.read()) != -1) {
			if (c == ((char) '\r') || c == ((char) '\n')) {
				if (c == ((char) '\r'))
					is.read();
				break;
			}
			byteArrayOutputStream.write(c);
		}
		if (c == -1 || byteArrayOutputStream.size() == 0)
			return null;
		final String line = byteArrayOutputStream.toString("UTF-8");
		byteArrayOutputStream.close();
		return line;
	}

}
